#pragma once

#include "Callbacks.h"
#include "Buffer.h"
#include <memory>
#include <any>

class Channel;
class EventLoop;
class Socket;


class TcpConnection : public std::enable_shared_from_this<TcpConnection> {
public:
    TcpConnection(EventLoop* loop, const std::string& name, int sockfd);
    ~TcpConnection();

    EventLoop* getLoop() const { return loop_; }
    const std::string& name() const { return name_; }
    std::string getLocalIpPort() const { return localIpPort_; }
    std::string getPeerIpPort() const { return peerIpPort_; }
    bool connected() const { return state_ == kConnected; }

    void send(Buffer* message);
    void send(const void* message, int len);
    void send(const std::string& message);
    void shutdown();
    void forceClose();

    void setContext(const std::any& context) { context_ = context; }
    const std::any& getContext() const { return context_; }
    std::any* getMutableContext() { return &context_; }

    void setConnectionCallback(const ConnectionCallback& cb) { connectionCallback_ = cb; }
    void setMessageCallback(const MessageCallback& cb) { messageCallback_ = cb; }
    void setWriteCompleteCallback(const WriteCompleteCallback& cb) { writeCompleteCallback_ = cb; }
    void setCloseCallback(const CloseCallback& cb) { closeCallback_ = cb; }

    // TcpServer接受一个新连接时调用 应该只调用一次
    void connectEstablished();
    // TcpServer从map中讲连接删除时调用 应该只调用一次
    void connectDestroyed();
    
    void startReading();
    bool isReading();
    int fd();
    
private:
    void handleRead();
    void handleWrite();
    void handleClose();
    void handleError();
    
    void sendStrInLoop(const std::string& message);
    void sendInLoop(const char* message, size_t len);
    void shutdownInLoop();
    void forceCloseInLoop();

    EventLoop* loop_;
    std::string name_;
    std::shared_ptr<Socket> socket_;
    std::shared_ptr<Channel> channel_;

    ConnectionCallback connectionCallback_;
    MessageCallback messageCallback_;
    WriteCompleteCallback writeCompleteCallback_;
    CloseCallback closeCallback_;
    
    Buffer inputBuffer_;
    Buffer outputBuffer_; 

    std::any context_;

    std::string localIpPort_;
    std::string peerIpPort_;

    enum StateE { kDisconnected, kConnecting, kConnected, kDisconnecting };
    void setState(StateE s) { state_ = s; }
    StateE state_;

};

